﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.RegularExpressions;
using System.Globalization;
using NLog;

namespace WOMPS
{
    public class Util
    {
        private static Logger logger = LogManager.GetCurrentClassLogger();

        public static void GetEpisode(ref Series s, SeriesFile sf)
        {
            if (logger.IsInfoEnabled)
            {
                logger.Info("Start GetEpisode");
            } 
            Episode e = new Episode();
            e = TryToGetEpisode(s.SeriesId, sf.AiredDate, s.LastModified);
            if (e != null)
            {
                e.FileSize = sf.FileSize;
                e.FileType = sf.FileType;
                e.LastModified = sf.LastModified;
                s.Episodes.Add(e);
            }
            s.EpisodeCounter++;
            if (logger.IsInfoEnabled)
            {
                logger.Info("End GetEpisode");
            } 
        }

        /// <summary>
        /// Attempts to get Episode information by date,  trys airdate first (hoping it is inbeded into the file name), then it will try by the files last modified date
        /// </summary>
        /// <param name="seriesId">series id</param>
        /// <param name="airDate">Date inbedded into the file</param>
        /// <param name="lastModified">Files last modified date</param>
        /// <returns></returns>
        public static Episode TryToGetEpisode(int seriesId, DateTime airDate, DateTime lastModified)
        {
            if (logger.IsInfoEnabled)
            {
                logger.Info("Start TryTpGetEpisode");
            } 
            //try and get by aridate
            Episode e = new Episode();
            if (airDate != null)
            {
                e = WebCalls.GetTVDBEpisode(seriesId, airDate);
            }
            if (e == null)
            {
                //now try by lastmodified date on the file
                e = RecursiveGetEpisode(seriesId, 1, lastModified);
            }
            if (logger.IsInfoEnabled)
            {
                logger.Info("End TryTpGetEpisode");
            } 
            return e;
        }

        /// <summary>
        /// Loops through itself trying to find an episode by a date.  Thought is that the last modified date could be off by a day or two 
        /// if like mine, the show could have been recorded a day or two ago, but MCEBuddy just got to it...
        /// </summary>
        /// <param name="seriesId">series Id</param>
        /// <param name="counter">counter, pass in a 1, to start off then will be updated by method</param>
        /// <param name="dt">date to start, i.e. last modified date</param>
        /// <returns></returns>
        private static Episode RecursiveGetEpisode(int seriesId, int counter, DateTime dt)
        {
            if (logger.IsInfoEnabled)
            {
                logger.Info("Start RecursiveGetEpisode");
            } 
            Episode e = WebCalls.GetTVDBEpisode(seriesId, dt);
            if (e == null && counter < 5)
            {
                e = RecursiveGetEpisode(seriesId, counter + 1, dt.AddDays(-1));
            }
            if (logger.IsInfoEnabled)
            {
                logger.Info("Start RecursiveGetEpisode");
            }
            return e;
        }
        /// <summary>
        /// Find if the series name if already in the list of series, will return the position of the series within the array
        /// </summary>
        /// <param name="sl">list of Series</param>
        /// <param name="seriesName">Series name to match on</param>
        /// <returns>int of where the series is in the array, if no match is found it returns null</returns>
        public static int? ShowInList(List<Series> sl, string seriesName)
        {
            if (logger.IsInfoEnabled)
            {
                logger.Info("Start ShowInList");
            }
            for (int i = 0; i < sl.Count; i++)
            {
                if (sl[i].SeriesName == seriesName)
                    return i;
            }
            if (logger.IsInfoEnabled)
            {
                logger.Info("Start ShowInList");
            }
            return null;
        }

        /// <summary>
        /// Convert Bytes to MegaBytes
        /// </summary>
        /// <param name="bytes">[long] number of Bytes</param>
        /// <returns>Double, Megabytes</returns>
        public static double ConvertBytesToMegabytes(long bytes)
        {
            if (logger.IsInfoEnabled)
            {
                logger.Info("Start ConvertBytesToMegabytes");
            }
            double d = (bytes / 1024f) / 1024f;
            if (logger.IsInfoEnabled)
            {
                logger.Info("End ConvertBytesToMegabytes");
            }
            return d;
        }

        /// <summary>
        /// Check to see if a string is a date
        /// </summary>
        /// <param name="isDate">A string that just might be a date</param>
        /// <returns>bool, if true it is a date, false it is not</returns>
        public static DateTime? IsDate(string isDate, MonitoredDirectory md)
        {
            if (logger.IsInfoEnabled)
            {
                logger.Info("Start IsDate");
            }
            string tempDate = isDate.Trim();
            DateTime temp;
            if (tempDate.Length > 5)
            {
                tempDate = tempDate.Remove(tempDate.Length - 4);
                string[] tempArray = tempDate.Split(md.DateDivider);
                if (tempArray.Count() == 3)
                {
                    string date = new DateTime(Convert.ToInt16(tempArray[2]), Convert.ToInt16(tempArray[0]), Convert.ToInt16(tempArray[1])).ToString();
                    if (DateTime.TryParse(date, out temp))
                    {
                        if (logger.IsInfoEnabled)
                        {
                            logger.Info("End IsDate - Date legit");
                        }
                        return new DateTime(Convert.ToInt16(tempArray[2]), Convert.ToInt16(tempArray[0]), Convert.ToInt16(tempArray[1]));
                    }
                    else
                    {
                        if (logger.IsInfoEnabled)
                        {
                            logger.Info("End IsDate - Date didn't parse");
                        }
                        return null;
                    }
                }
                else
                {
                    if (logger.IsInfoEnabled)
                    {
                        logger.Info("End IsDate - Split on date didn't contain 3 elements");
                    }
                    return null;
                }
            }
            else
            {
                if (logger.IsInfoEnabled)
                {
                    logger.Info("End IsDate - Date length greater than 5");
                }
                return null;
            }
        }

        public static bool IsRightFileType(string fileType)
        {
            switch (fileType)
            {
                case ".avi":
                    return true;
                case ".mp4":
                    return true;
                case ".mkv":
                    return true;
                default:
                    return false;
            }
        }

        public bool IsValidEmail(string strIn)
        {
            if (logger.IsInfoEnabled)
            {
                logger.Info("Start IsValidEmail");
            }
            bool invalid = false;
            if (String.IsNullOrEmpty(strIn))
            {
                if (logger.IsInfoEnabled)
                {
                    logger.Info("End IsValidEmail - empty string");
                }
                return false;
            }
            // Use IdnMapping class to convert Unicode domain names. 
            try
            {
                strIn = Regex.Replace(strIn, @"(@)(.+)$", this.DomainMapper,
                                      RegexOptions.None, TimeSpan.FromMilliseconds(200));
            }
            catch (RegexMatchTimeoutException exc)
            {
                logger.FatalException("IsValidEmail", exc);
                return false;
            }

            if (invalid)
            {
                if (logger.IsInfoEnabled)
                {
                    logger.Info("End IsValidEmail - not valid domain");
                }
                return false;
            }
            // Return true if strIn is in valid e-mail format. 
            try
            {
                bool b = Regex.IsMatch(strIn,
                      @"^(?("")("".+?(?<!\\)""@)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])@))" +
                      @"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$",
                      RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250));
                if (logger.IsInfoEnabled)
                {
                    logger.Info("End IsValidEmail - " + b.ToString());
                }
                return b;
            }
            catch (RegexMatchTimeoutException exc)
            {
                logger.FatalException("IsValidEmail", exc);
                return false;
            }
        }
        private string DomainMapper(Match match)
        {
            // IdnMapping class with default property values.
            IdnMapping idn = new IdnMapping();

            string domainName = match.Groups[2].Value;
            try
            {
                domainName = idn.GetAscii(domainName);
            }
            catch (ArgumentException)
            {
                bool invalid = true;
            }
            return match.Groups[1].Value + domainName;
        }

    }
}
